package helper.scxml.strategy

import helper.base.A2LHM
import helper.base.LHMHelper.A2LHMExpand.add
import helper.base.LHMHelper.A2LHMExpand.merge
import helper.base.RandomHelper.Expand.getRandomE
import helper.base.RandomHelper.getRandom
import helper.base.RegexHelper
import helper.base.StateHelper.EventChoice
import helper.base.StringHelper.removeEmptyLine
import helper.base.math.MathHelper.MapListMerger.getCombinedProductMap
import helper.base.string.ToLStringHelper.IToL1String
import helper.base.string.ToStrHelper.IToStr
import helper.base.string.ToStrHelper.TabStringUnit.Companion.makeTabStringUnit
import helper.scxml.strategy.StrategyHelper.TimedEventHelper.TimedEvent.Companion.makeTimedEvent
import java.util.*

//最新的
// 定义 StrategyHelper 对象，包含时间事件选择相关的辅助类和方法
object StrategyHelper {
    // 定义与时间事件选择相关的辅助类
    object TimedEventHelper {
        // 定义与时间事件选择相关的接口，扩展了 IToL1String 接口
        interface ITimedEvent : IToL1String {
            // 获取时间事件选择
            fun getTimedEvent(): TimedEvent

            // 获取时间事件选择及其权重的 LinkedHashMap
            fun getTimedEventWeightLHM(): A2LHM<TimedEvent, Double>
        }

        // 从 A2LHM 中随机选择一个 ITimeEventChoice，并获取其时间事件选择
        fun A2LHM<ITimedEvent, Double>.getMTimedEvent(): TimedEvent? {
            val randomE = this.getRandomE()
            return randomE?.getTimedEvent()
        }

        // 从 A2LHM 中获取所有时间事件选择及其权重的 LinkedHashMap
        fun A2LHM<ITimedEvent, Double>.getTimedEventWeightLHM(): A2LHM<TimedEvent, Double> {
            val lhm = A2LHM<TimedEvent, Double>()
            this.forEach { (k, v) ->
                k.getTimedEventWeightLHM().forEach { (t, u) ->
                    lhm.add(t, v * u)
                }
            }
            return lhm
        }

        // 从时间事件选择列表中合并并随机选择一个时间事件选择
        fun List<A2LHM<ITimedEvent, Double>>.getMTimedEvent(): TimedEvent? {
            return this.merge().getMTimedEvent()
        }

        // 从时间事件选择列表中合并并获取所有时间事件选择及其权重的 LinkedHashMap
        fun List<A2LHM<ITimedEvent, Double>>.getTimedEventWeightLHM(): A2LHM<TimedEvent, Double> {
            return this.merge().getTimedEventWeightLHM()
        }

        // 定义 TimeEventChoice 类，扩展了 EventChoice 类和 ITimeEventChoice 接口
        class TimedEvent(val time: Int, event: String) : EventChoice(event), ITimedEvent {
            companion object {
                fun makeTimedEvent(time: Int, event: String) = TimedEvent(time, event)

                // 将字符串转换为 TimeEventChoice 实例的静态方法
                fun String.toTimedEvent(): TimedEvent? {
                    val matchResult = """^${RegexHelper.intRegex},(.+)$""".toRegex().find(this)
                    return matchResult?.let {
                        val (time, event) = it.destructured
                        makeTimedEvent(time.toInt(), event)
                    }
                }
            }

            object Expand {
                // 提供 List<TimeEventChoice> 的深拷贝方法
                fun List<TimedEvent>.deepCopy(): List<TimedEvent> {
                    val newList = ArrayList<TimedEvent>(this.size)
                    for (item in this) {
                        // 假设 TimeEventChoice 类型有一个 copy 函数
                        newList.add(item.clone())
                    }
                    return newList
                }

                // 提供 List<A2LHM<TimeEventChoice, Double>> 的组合产品映射方法
                fun List<A2LHM<TimedEvent, Double>>.getCombinedProductMap(): A2LHM<List<TimedEvent>, Double> {
                    return getCombinedProductMap(this) {
                        it.deepCopy()
                    }
                }
            }

            // 定义解构声明，允许将 TimeEventChoice 实例解构为时间和事件
            operator fun component1() = time
            operator fun component2() = event

            override fun getTimedEvent() = this

            override fun getTimedEventWeightLHM() = linkedMapOf(this to 1.0)

            override fun clone() = makeTimedEvent(time, event)

            override fun toString() = "(${time},${event})"

            override fun toL1String() = "(${time},${event})"
        }

        // 定义一个最小时间优先队列，用于管理 TimeEventChoice 实例
        class TimedEventMinTimePQ {
            companion object {
                fun makeTimedEventMinTimePQ() = TimedEventMinTimePQ()
            }

            // 优先队列，根据 TimeEventChoice 实例的时间排序
            val heap: PriorityQueue<TimedEvent> = PriorityQueue<TimedEvent>(
                compareBy {
                    it.time
                },
            )

            // 检查队列中是否包含指定事件
            fun containsEvent(event: String): Boolean {
                return heap.any {
                    it.event == event
                }
            }

            // 检查队列中是否不包含指定事件
            fun notContainsEvent(event: String) = !containsEvent(event)

            /**
             * 从优先队列中弹出所有具有最小时间值的 TimeEventChoice 实例。
             *
             * 此方法首先检查优先队列的首元素（即时间值最小的元素），并将其作为基准。
             * 然后，它会继续从队列中弹出所有时间值与此基准相同的元素。
             * 这些元素被收集到一个列表中并返回给调用者。
             *
             * 在弹出这些具有最小时间值的元素后，此方法还会更新队列中剩余元素的时间值，
             * 使每个元素的时间值减去已弹出元素的最小时间值，以保持时间的相对性。
             *
             * @return 包含所有最小时间 TimeEventChoice 实例的 ArrayList。
             */
            fun pollAllMinTime(): ArrayList<TimedEvent> {
                val minTimeItems = arrayListOf<TimedEvent>() // 存储具有最小时间的元素
                val firstItem = heap.poll() ?: return minTimeItems // 弹出并获取最小时间的元素，如果队列为空，则返回空列表

                val minTime = firstItem.time // 记录最小时间值
                minTimeItems.add(firstItem) // 将第一个元素添加到结果列表中

                // 循环检查并弹出所有时间值与最小时间相等的元素
                while (heap.isNotEmpty() && heap.peek().time == minTime) {
                    minTimeItems.add(heap.poll()) // 弹出并添加到结果列表中
                }

                // 创建一个新的优先队列，用于更新剩余元素的时间
                val updatedQueue = PriorityQueue<TimedEvent>(compareBy { it.time })
                // 更新队列中每个元素的时间值，然后添加到新队列中
                while (heap.isNotEmpty()) {
                    val current = heap.poll() // 弹出元素
                    // 创建一个时间更新后的新 TimeEventChoice 实例，并添加到新队列中
                    updatedQueue.add(TimedEvent(current.time - minTime, current.event))
                }

                // 使用更新后的队列替换原队列
                heap.addAll(updatedQueue)
                return minTimeItems // 返回所有具有最小时间的元素列表
            }

            // 深克隆当前 TimeEventChoiceMinTimePriorityQueue 实例
            fun deepClone(): TimedEventMinTimePQ {
                val clone = TimedEventMinTimePQ()
                // 克隆 PriorityQueue
                for (item in heap) {
                    clone.heap.add(item.clone()) // 使用 data class 的 copy 方法
                }
                return clone
            }

            // 自定义返回字符串的函数
            // 获取优先队列中所有元素的字符串表示
            fun getString(): String {
                val elementsAsString = heap.joinToString(separator = ",") {
                    it.toString()
                }
                return "(${elementsAsString})"
            }
        }

        // 定义一个表示时间范围内事件选择的类，扩展了 EventChoice 类和 ITimeEventChoice、IToStr 接口
        class RangeTimedEvent(var rangeTime: IntRange, event: String) : EventChoice(event), ITimedEvent, IToStr {
            companion object {
                fun makeRangeTimedEvent(rangeTime: IntRange, event: String) = RangeTimedEvent(rangeTime, event)
            }

            // 实现 ITimeEventChoice 接口的方法，从时间范围内随机选择一个时间创建 TimeEventChoice 实例
            override fun getTimedEvent() = makeTimedEvent(rangeTime.getRandom(), event)

            /**
             * 获取时间范围内所有可能的 TimeEventChoice 及其权重的 LinkedHashMap。
             *
             * 此方法遍历整个时间范围，为每个时间点创建一个 TimeEventChoice 实例，并计算其权重。
             * 权重是基于时间范围内时间点的总数计算的，确保所有时间点的权重加起来为 1。
             * 这对于需要根据时间范围内的不同时间点做出随机选择时特别有用，每个时间点被平等地考虑。
             *
             * @return A2LHM<TimeEventChoice, Double>，其中键是时间范围内的每个可能的 TimeEventChoice，
             *         值是对应的权重，表示为 Double 类型。权重分布均匀，以确保每个时间点被公平考虑。
             */
            override fun getTimedEventWeightLHM(): A2LHM<TimedEvent, Double> {
                val lhm = A2LHM<TimedEvent, Double>() // 创建一个空的 LinkedHashMap 存储结果
                val count = rangeTime.count() // 获取时间范围内的总时间点数
                rangeTime.forEach { // 遍历每个时间点
                    // 为每个时间点创建一个 TimeEventChoice 实例并添加到 LinkedHashMap 中
                    // 同时计算每个时间点的权重，权重为 1 除以时间点的总数
                    lhm.add(
                        makeTimedEvent(it, event), // 创建 TimeEventChoice 实例
                        1.0 / count, // 计算权重
                    )
                }
                return lhm // 返回填充了 TimeEventChoice 实例及其权重的 LinkedHashMap
            }

            override fun toL1String() = "(${rangeTime},${event})"

            operator fun component1() = rangeTime
            operator fun component2() = event

            // 重写 toStr 方法，返回 RangeTimeEventChoice 的详细字符串表示
            override fun toStr(tabNum: Int): String {
                val sb = StringBuilder()
                val tsu = makeTabStringUnit(tabNum)
                sb.append("${tsu.tabNumStr0}RangeTimeEventChoice(${toL1String()})\n")
                return sb.toString().removeEmptyLine()
            }
        }
    }
}